Passed
Push — master ( 06bde6...6d2f62 )
by Paul
04:59
created

Search.onUnassign   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 3

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 1
nc 1
nop 0
dl 0
loc 3
rs 10
c 0
b 0
f 0
1
/** global: GLSR, jQuery */
2
;(function( _, wp, x ) {
3
4
	'use strict';
5
6
	var Search = function( selector, options ) {
7
		this.el = x( selector );
8
		this.options = options;
9
		this.searchTerm = null;
10
		this.init_();
11
	};
12
13
	Search.prototype = {
14
		defaults: {
15
			action: null,
16
			exclude: [],
17
			onInit: null,
18
			onResultClick: null,
19
			results: {},
20
			selected: -1,
21
			selectedClass: 'glsr-selected-result',
22
			selectorEntries: '.glsr-strings-table tbody',
23
			selectorResults: '.glsr-search-results',
24
			selectorSearch: '.glsr-search-input',
25
			// entriesEl
26
			// resultsEl
27
			// searchEl
28
		},
29
30
		/** @return void */
31
		init_: function() {
32
			this.options = x.extend( {}, this.defaults, this.options );
33
			if( !this.el.length )return;
34
			this.options.entriesEl = this.el.parent().find( this.options.selectorEntries );
35
			this.options.resultsEl = this.el.find( this.options.selectorResults );
36
			this.options.searchEl = this.el.find( this.options.selectorSearch );
37
			this.options.searchEl.attr( 'aria-describedby', 'live-search-desc' );
38
			if( typeof this.options.onInit === 'function' ) {
39
				this.options.onInit.call( this );
40
			}
41
			this.initEvents_();
42
		},
43
44
		/** @return void */
45
		initEvents_: function() {
46
			this.options.searchEl.on( 'input', _.debounce( this.onSearchInput_.bind( this ), 500 ));
47
			this.options.searchEl.on( 'keyup', this.onSearchKeyup_.bind( this ));
48
			this.options.searchEl.on( 'keydown keypress', function( ev ) {
49
				if( GLSR.keys.ENTER !== ev.which )return;
50
				ev.preventDefault();
51
			});
52
			x( document ).on( 'click', this.onDocumentClick_.bind( this ));
53
			x( document ).on( 'keydown', this.onDocumentKeydown_.bind( this ));
54
		},
55
56
		/** @return void */
57
		abort_: function() {
58
			if( 'undefined' === typeof this.searchRequest )return;
59
			this.searchRequest.abort();
60
		},
61
62
		/** @return void */
63
		clearResults_: function() {
64
			this.abort_();
65
			this.options.resultsEl.empty();
66
			this.el.removeClass( 'is-active' );
67
			x( 'body' ).removeClass( 'glsr-focus' );
68
		},
69
70
		/** @return void */// Manage entries
71
		deleteEntry_: function( index ) {
72
			var row = this.options.entriesEl.children( 'tr' ).eq( index );
73
			var search = this;
74
			row.find( 'td' ).css({ backgroundColor:'#faafaa' });
75
			row.fadeOut( 350, function() {
76
				x( this ).remove();
77
				search.options.results = {};
78
				search.reindexRows_();
79
				search.setVisibility_();
80
			});
81
		},
82
83
		/** @return void */
84
		displayResults_: function( items ) {
85
			x( 'body' ).addClass( 'glsr-focus' );
86
			this.options.resultsEl.append( items );
87
			this.options.resultsEl.children( 'span' ).on( 'click', this.onResultClick_.bind( this ));
88
		},
89
90
		/** @return void */// Manage entries
91
		makeSortable_: function() {
92
			this.options.entriesEl.on( 'click', 'a.delete', this.onEntryDelete_.bind( this ));
93
			this.options.entriesEl.sortable({
94
				items: 'tr',
95
				tolerance: 'pointer',
96
				start: function( ev, ui ) {
97
					ui.placeholder.height( ui.helper[0].scrollHeight );
98
				},
99
				sort: function( ev, ui ) {
100
					var top = ev.pageY - x( this ).offsetParent().offset().top - ( ui.helper.outerHeight( true ) / 2 );
101
					ui.helper.css({
102
						top: top + 'px',
103
					});
104
				},
105
			});
106
		},
107
108
		/** @return void */
109
		navigateResults_: function( diff ) {
110
			this.options.selected += diff;
111
			this.options.results.removeClass( this.options.selectedClass );
112
			if( this.options.selected < 0 ) {
113
				// reached the start (should now allow keydown scroll)
114
				this.options.selected = -1;
115
				this.options.searchEl.focus();
116
			}
117
			if( this.options.selected >= this.options.results.length ) {
118
				// reached the end (should now allow keydown scroll)
119
				this.options.selected = this.options.results.length - 1;
120
			}
121
			if( this.options.selected >= 0 ) {
122
				this.options.results.eq( this.options.selected )
123
					.addClass( this.options.selectedClass )
124
					.focus();
125
			}
126
		},
127
128
		/** @return void */
129
		onDocumentClick_: function( ev ) {
130
			if( x( ev.target ).find( this.el ).length && x( 'body' ).hasClass( 'glsr-focus' )) {
131
				this.clearResults_();
132
			}
133
		},
134
135
		/** @return void */
136
		onDocumentKeydown_: function( ev ) {
137
			if( !this.options.results )return;
138
			if( GLSR.keys.ESC === ev.which ) {
139
				this.clearResults_();
140
			}
141
			if( GLSR.keys.ENTER === ev.which || GLSR.keys.SPACE === ev.which ) {
142
				var selected = this.options.resultsEl.find( '.' + this.options.selectedClass );
143
				if( selected ) {
144
					selected.trigger( 'click' );
145
				}
146
			}
147
			if( GLSR.keys.UP === ev.which ) {
148
				ev.preventDefault();
149
				this.navigateResults_(-1);
150
			}
151
			if( GLSR.keys.DOWN === ev.which ) {
152
				ev.preventDefault();
153
				this.navigateResults_(1);
154
			}
155
		},
156
157
		/** @return void */// Manage entries
158
		onEntryDelete_: function( ev ) {
159
			ev.preventDefault();
160
			this.deleteEntry_( x( ev.target ).closest( 'tr' ).index() );
161
		},
162
163
		/** @return void */
164
		onResultClick_: function( ev ) {
165
			ev.preventDefault();
166
			if( typeof this.options.onResultClick === 'function' ) {
167
				this.options.onResultClick.call( this, ev );
168
			}
169
			this.clearResults_();
170
		},
171
172
		/** @return void */
173
		onSearchInput_: function( ev ) {
174
			this.abort_();
175
			if( this.searchTerm === ev.target.value && this.options.results.length ) {
176
				return this.displayResults_( this.options.results );
177
			}
178
			this.options.resultsEl.empty();
179
			this.options.selected = -1;
180
			this.searchTerm = ev.target.value;
181
			if( this.searchTerm === '' ) {
182
				return this.reset_();
183
			}
184
			this.el.addClass( 'is-active' );
185
			this.searchRequest = wp.ajax.post( GLSR.action, {
186
				request: {
187
					action: this.options.action,
188
					exclude: this.options.exclude,
189
					nonce: this.el.find( '#_search_nonce' ).val(),
190
					search: this.searchTerm,
191
				},
192
			}).done( function( response ) {
193
				this.el.removeClass( 'is-active' );
194
				this.displayResults_( response.items ? response.items : response.empty );
195
				this.options.results = this.options.resultsEl.children();
196
				delete this.searchRequest;
197
			}.bind( this ));
198
		},
199
200
		/** @return void */
201
		onSearchKeyup_: function( ev ) {
202
			if( GLSR.keys.ESC === ev.which ) {
203
				this.reset_();
204
			}
205
			if( GLSR.keys.ENTER === ev.which ) {
206
				this.onSearchInput_( ev );
207
				ev.preventDefault();
208
			}
209
		},
210
211
		/** @return void */// Manage entries
212
		onUnassign_: function( ev ) {
213
			ev.preventDefault();
214
			var assigned = this.el.find( '.description' );
215
			this.el.find( 'input#assigned_to' ).val( '' );
216
			assigned.find( 'a' ).css({ color:'#c00' });
217
			assigned.fadeOut( 'fast', function() {
218
				x( this ).html( '' ).show();
219
			});
220
		},
221
222
		/** @return void */// Manage entries
223
		reindexRows_: function() {
224
			var search = this;
225
			this.options.exclude = [];
226
			this.options.entriesEl.children( 'tr' ).each( function( index ) {
227
				x( this ).find( '.glsr-string-td2' ).children().filter( ':input' ).each( function() {
228
					var input = x( this );
229
					var name = input.attr( 'name' ).replace( /\[\d+\]/i, '[' + index + ']' );
230
					input.attr( 'name', name );
231
					if( input.is( '[data-id]' )) {
232
						search.options.exclude.push({ id: input.val() });
233
					}
234
				});
235
			});
236
		},
237
238
		/** @return void */
239
		reset_: function() {
240
			this.clearResults_();
241
			this.options.results = {};
242
			this.options.searchEl.val( '' );
243
		},
244
245
		/** @return void */// Manage entries
246
		setVisibility_: function() {
247
			var action = this.options.entriesEl.children().length > 0 ? 'remove' : 'add';
248
			this.options.entriesEl.parent()[action + 'Class']( 'glsr-hidden' );
249
		},
250
	};
251
252
	GLSR.Search = Search;
253
})( window._, window.wp, jQuery );
254